﻿using System;
using System.Collections.Generic;
using System.Globalization;
using Nop.Core;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Payments.PayPalHosted.PayPalAPI;
using Nop.Services.Payments;
using System.Linq;

namespace Nop.Plugin.Payments.PayPalHosted.Services
{
    public class PayPalRequestService : IPayPalRequestService
    {
        private readonly IPayPalCurrencyCodeParser _payPalCurrencyCodeParser;
        private readonly IPayPalRecurringPaymentsService _payPalRecurringPaymentsService;
        private readonly PayPalHostedPaymentSettings _payPalHostedPaymentSettings;
        private readonly IStoreContext _storeContext;

        public PayPalRequestService(IPayPalCurrencyCodeParser payPalCurrencyCodeParser,
        IPayPalRecurringPaymentsService payPalRecurringPaymentsService,
        PayPalHostedPaymentSettings payPalHostedPaymentSettings,
        IStoreContext storeContext)
        {
            _payPalCurrencyCodeParser = payPalCurrencyCodeParser;
            _payPalRecurringPaymentsService = payPalRecurringPaymentsService;
            _payPalHostedPaymentSettings = payPalHostedPaymentSettings;
            _storeContext = storeContext;
        }

        public string GetVersion()
        {
            return "98.0";
        }

        public DoCaptureReq GetDoCaptureRequest(CapturePaymentRequest capturePaymentRequest)
        {
            return new DoCaptureReq
                       {
                           DoCaptureRequest = new DoCaptureRequestType
                                                  {
                                                      Amount = new BasicAmountType
                                                                   {
                                                                       Value = Math.Round(capturePaymentRequest.Order.OrderTotal, 2).ToString("N", new CultureInfo("en-us")),
                                                                       currencyID = _payPalCurrencyCodeParser.GetCurrencyCodeType(capturePaymentRequest.Order.CustomerCurrencyCode)
                                                                   },
                                                      AuthorizationID = capturePaymentRequest.Order.CaptureTransactionId,
                                                      CompleteType = CompleteCodeType.Complete,
                                                      InvoiceID = capturePaymentRequest.Order.OrderGuid.ToString(),
                                                      Version = GetVersion(),
                                                      MsgSubID = capturePaymentRequest.Order.OrderGuid + "-capture"
                                                  },

                       };
        }

        public RefundTransactionReq GetRefundTransactionRequest(RefundPaymentRequest refundPaymentRequest)
        {
            var transactionId = refundPaymentRequest.Order.CaptureTransactionId;
            var refundType = refundPaymentRequest.IsPartialRefund ? RefundType.Partial : RefundType.Full;

            return new RefundTransactionReq
            {
                RefundTransactionRequest = new RefundTransactionRequestType
                {
                    RefundType = refundType,
                    RefundTypeSpecified = true,
                    Version = GetVersion(),
                    TransactionID = transactionId,
                    Amount = new BasicAmountType
                    {
                        Value = Math.Round(refundPaymentRequest.AmountToRefund, 2).ToString("N", new CultureInfo("en-us")),
                        currencyID = _payPalCurrencyCodeParser.GetCurrencyCodeType(refundPaymentRequest.Order.CustomerCurrencyCode)
                    },
                    MsgSubID = string.Format("{0}-{1}-{2:0.00}", refundPaymentRequest.Order.OrderGuid, refundPaymentRequest.IsPartialRefund, refundPaymentRequest.AmountToRefund)
                }
            };
        }

        public DoVoidReq GetVoidRequest(VoidPaymentRequest voidPaymentRequest)
        {
            string transactionId = voidPaymentRequest.Order.AuthorizationTransactionId;
            if (String.IsNullOrEmpty(transactionId))
                transactionId = voidPaymentRequest.Order.CaptureTransactionId;

            return new DoVoidReq
            {
                DoVoidRequest = new DoVoidRequestType
                {
                    Version = GetVersion(),
                    AuthorizationID = transactionId,
                    MsgSubID = voidPaymentRequest.Order.OrderGuid + "-void"
                }
            };
        }

        public CreateRecurringPaymentsProfileReq GetCreateRecurringPaymentsProfileRequest(ProcessPaymentRequest processPaymentRequest)
        {
            var req = new CreateRecurringPaymentsProfileReq
            {
                CreateRecurringPaymentsProfileRequest =
                    new CreateRecurringPaymentsProfileRequestType
                    {
                        Version = GetVersion(),
                        CreateRecurringPaymentsProfileRequestDetails = _payPalRecurringPaymentsService.GetCreateRecurringPaymentProfileRequestDetails(processPaymentRequest)
                    }
            };


            return req;
        }

        public ManageRecurringPaymentsProfileStatusReq GetCancelRecurringPaymentRequest(
            CancelRecurringPaymentRequest cancelRecurringPaymentRequest)
        {
            return new ManageRecurringPaymentsProfileStatusReq
            {
                ManageRecurringPaymentsProfileStatusRequest =
                    new ManageRecurringPaymentsProfileStatusRequestType
                    {
                        Version = GetVersion(),
                        ManageRecurringPaymentsProfileStatusRequestDetails =
                            new ManageRecurringPaymentsProfileStatusRequestDetailsType
                            {
                                Action = StatusChangeActionType.Cancel,
                                ProfileID = cancelRecurringPaymentRequest.Order.OrderGuid.ToString()
                            },

                    }
            };
        }

        public BMCreateButtonReq GetBMCreateButtonRequest(Order order)
        {
            return new BMCreateButtonReq
                       {
                           BMCreateButtonRequest =
                               new BMCreateButtonRequestType
                                   {
                                       ButtonCode = ButtonCodeType.CLEARTEXT,
                                       ButtonCodeSpecified = true,
                                       ButtonType = ButtonTypeType.PAYMENT,
                                       ButtonTypeSpecified = true,
                                       OptionDetails = new[]
                                                           {
                                                               new OptionDetailsType
                                                                   {
                                                                       OptionSelectionDetails =
                                                                           new[]
                                                                               {
                                                                                   new OptionSelectionDetailsType
                                                                                       {
                                                                                           OptionType = OptionTypeListType.FULL,
                                                                                           Price = Math.Round(order.OrderSubtotalInclTax, 2).ToString("0.00"),
                                                                                       }
                                                                               },
                                                                   }
                                                           },


                                       Version = GetVersion(),
                                       ButtonVar = GetButtonVar(order)
                                   }
                       };
        }

        private string[] GetButtonVar(Order order)
        {
            var dictionary = new Dictionary<string, string>();
            dictionary["cmd"] = "_hosted-payment";
            dictionary["business"] = _payPalHostedPaymentSettings.DoNotHaveBusinessAccount
                                          ? _payPalHostedPaymentSettings.EmailAddress
                                          : _payPalHostedPaymentSettings.BusinessId;
            dictionary["subtotal"] = order.OrderSubtotalInclTax.ToString("0.00");
            dictionary["return"] =
                new Uri(new Uri(_storeContext.CurrentStore.Url), "Plugins/PaymentPayPalHosted/ReturnHandler")
                    .ToString();
            dictionary["notify_url"] =
                new Uri(new Uri(_storeContext.CurrentStore.Url), "Plugins/PaymentPayPalHosted/IPNHandler")
                    .ToString();
            //dictionary["cancel_return"] =
            //    new Uri(new Uri(_storeContext.CurrentStore.Url), "cart")
            //        .ToString();
            dictionary["paymentaction"] = "sale";
            dictionary["currency_code"] = order.CustomerCurrencyCode;
            dictionary["tax"] = order.OrderTax.ToString("0.00");
            dictionary["shipping"] = order.OrderShippingExclTax.ToString("0.00");
            var billingAddress = order.BillingAddress;
            if (billingAddress != null)
            {
                dictionary["address1"] = billingAddress.Address1;
                dictionary["address2"] = billingAddress.Address2;
                dictionary["city"] = billingAddress.City;
                var stateProvince = billingAddress.StateProvince;
                if (stateProvince != null)
                    dictionary["state"] = stateProvince.Abbreviation;
                var country = billingAddress.Country;
                if (country != null)
                    dictionary["country"] = country.TwoLetterIsoCode;
                dictionary["zip"] = billingAddress.ZipPostalCode;
            }
            dictionary["item_name"] = "Payment for order #" + order.Id;
            dictionary["custom"] = order.OrderGuid.ToString();
            dictionary["bn"] = "nopCommerce _Cart_HostedPro";
            return dictionary.Select(pair => string.Format("{0}={1}", pair.Key, pair.Value)).ToArray();
        }
    }
}